package com.vegetable.modules.service.baseData.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.common.utils.Constant;
import com.vegetable.common.utils.PageUtils;
import com.vegetable.common.utils.R;
import com.vegetable.modules.entity.baseData.FundAccount;
import com.vegetable.modules.entity.finance.FinanceAnalyse;
import com.vegetable.modules.entity.finance.po.AgentDeliveryStatisticsPO;
import com.vegetable.modules.entity.finance.po.FinancialCollectionStatisticsPO;
import com.vegetable.modules.entity.finance.po.PurchaseDeliveryStatisticsPO;
import com.vegetable.modules.entity.finance.vo.FinancialCollectionStatistics;
import com.vegetable.modules.entity.finance.vo.PaymentAgentStatisticsVO;
import com.vegetable.modules.entity.finance.vo.PaymentPurchaseStatisticsVO;
import com.vegetable.modules.entity.outbound.SalesOut;
import com.vegetable.modules.entity.wx.WXApproval;
import com.vegetable.modules.mapper.baseData.FundAccountMapper;
import com.vegetable.modules.mapper.finance.FinanceAnalyseMapper;
import com.vegetable.modules.mapper.finance.FinancialCollectionDetailMapper;
import com.vegetable.modules.mapper.finance.PaymentPurchaseMapper;
import com.vegetable.modules.mapper.finance.TransactionsMapper;
import com.vegetable.modules.mapper.outbound.SalesOutMapper;
import com.vegetable.modules.mapper.wx.WXApprovalDao;
import com.vegetable.modules.service.baseData.IFundAccountService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 资金账户 服务实现类
 * </p>
 *
 * @author wangruijie
 * @since 2024-03-04
 */
@Slf4j
@Service
@AllArgsConstructor
public class FundAccountServiceImpl extends ServiceImpl<FundAccountMapper, FundAccount> implements IFundAccountService {
    private FundAccountMapper fundAccountMapper;
    private FinancialCollectionDetailMapper financialCollectionDetailMapper;
    private PaymentPurchaseMapper paymentPurchaseMapper;
    private FinanceAnalyseMapper financeAnalyseMapper;
    private WXApprovalDao wxApprovalDao;
    private SalesOutMapper salesOutMapper;
    private TransactionsMapper transactionsMapper;

    /**
     * 资金账户
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String accountName = (String)params.get("accountName");
        String isDel = (String)params.get("isDel");
        Integer isDel_int = 0;
        if (StringUtils.isNotBlank(isDel)){
            isDel_int = Integer.valueOf(isDel);
        }
//        IPage<FundAccount> page = this.page(
//                new Query<FundAccount>().getPage(params),
//                new QueryWrapper<FundAccount>()
//                        .like(StringUtils.isNotBlank(accountName),"account_name", accountName)
//                        .eq(ObjectUtils.isNotEmpty(isDel_int),"is_del", isDel_int)
//                        .orderByDesc("create_time")
//        );
        long curPage = 1;
        long limit = 10;

        if(params.get(Constant.PAGE) != null){
            curPage = Long.parseLong((String)params.get(Constant.PAGE));
        }
        if(params.get(Constant.LIMIT) != null){
            limit = Long.parseLong((String)params.get(Constant.LIMIT));
        }
        IPage<FundAccount> result = baseMapper.selectPage(new Page<>(curPage, limit), isDel, accountName);
        return new PageUtils(result);
    }

    @Override
    public void addReceipts(Long accountId, BigDecimal changeNumber, Constant.MoneyTYPE changeType, String relateDocNo, Long relateOrderId, String target) {
        // todo 不再更新账户总收入、总支出及流水信息
//        // 更新账户总费用
//        FundAccount fa = getById(accountId);
//        fa.setId(accountId);
//        if(Constant.MoneyTYPE.isOutType(changeType.getValue())){
//            BigDecimal totalExpenditure = NumberUtil.add(fa.getTotalExpenditure(), changeNumber);
//            fa.setTotalExpenditure(totalExpenditure);
////            fa.setTotalBalance(NumberUtil.mul(fa.getTotalBalance(), changeNumber));
//        } else {
//            BigDecimal totalReceipts = NumberUtil.add(fa.getTotalReceipts(), changeNumber);
//            fa.setTotalReceipts(totalReceipts);
////            fa.setTotalBalance(NumberUtil.add(fa.getTotalBalance(), changeNumber));
//        }
//        fa.setTotalBalance(null);
//        this.updateById(fa);
//        // 更新账户变动记录
//        FundAccountDetail fad = new FundAccountDetail();
//        fad.setAccountId(accountId);
//        fad.setAccountName(fa.getAccountName());
//        fad.setChangeNumber(changeNumber);
//        fad.setChangeState(Constant.MoneyTYPE.isOutType(changeType.getValue()) ? 1 : 0);
//        fad.setChangeType(changeType.getValue());
//        fad.setRelateOrderId(relateOrderId);
//        fad.setRelateDocNo(relateDocNo);
//        fad.setTarget(target);
//        fundAccountDetailMapper.insert(fad);
    }

    public BigDecimal getSalesForMonth(List<Map<String, Object>> data, String month) {
        // 处理所有可能的null情况
        List<Map<String, Object>> bdList = Optional.ofNullable(data)
                .orElse(Collections.emptyList())
                .stream()
                .filter(Objects::nonNull) // 过滤掉null的Map
                .filter(map -> map.get("monthMark").equals(month))
                .collect(Collectors.toList());
        BigDecimal tmp = CollectionUtil.isNotEmpty(bdList) ? new BigDecimal(bdList.get(0).get("totalMoney").toString()) : BigDecimal.ZERO;
        return tmp;
    }

    @Override
    public R financialAnalysis(Integer chartRange) {
        Date endTime = new Date();
        Date startTime = DateUtil.offsetMonth(endTime, -chartRange);
        //
        List<String> monthList = generateMonthList(endTime, startTime);
        JSONObject result = new JSONObject();
        List<Map<String, Object>> salesOutData = salesOutMapper.analysisSalesOut(startTime, endTime);
        List<Map<String, Object>> transINCOME = transactionsMapper.analysisTransINCOME(startTime, endTime);
        List<Map<String, Object>> transEXPENSE = transactionsMapper.analysisTransEXPENSE(startTime, endTime);

        List md = new ArrayList<>();
//        List<FinanceAnalyse> faList = financeAnalyseMapper.selectByYear(DateUtil.year(new Date()));
        List t1 = new ArrayList();
        t1.add("product");
        t1.add("销售额");
        t1.add("支出");
        t1.add("收入");
        md.add(t1);
        for(String monthMark : monthList){
            List dd = new ArrayList();
            dd.add(monthMark);
            dd.add(getSalesForMonth(salesOutData, monthMark));
            dd.add(getSalesForMonth(transEXPENSE, monthMark));
            dd.add(getSalesForMonth(transINCOME, monthMark));
            md.add(dd);
        }
        result.put("monthData", md);

        List<FundAccount> fundAccountList = fundAccountMapper.selectList(new QueryWrapper<>());
        Map<String, Object> totalAnalyse = new HashMap<>();
        PaymentAgentStatisticsVO paymentAgentStatisticsVO = paymentPurchaseMapper.agentDeliveryStatistics2(null);
        PaymentPurchaseStatisticsVO paymentPurchaseStatisticsVO = paymentPurchaseMapper.purchaseDeliveryStatistics2(null);
        IPage<FinancialCollectionStatistics> iPage = financialCollectionDetailMapper.queryFinancialCollectionListByCustomer(new Page(1, Long.MAX_VALUE), new FinancialCollectionStatisticsPO(startTime, endTime));
        totalAnalyse.put("expenses", transEXPENSE.stream().map(el -> new BigDecimal(el.get("totalMoney").toString())).reduce(BigDecimal.ZERO, BigDecimal::add));
        BigDecimal totalSales = salesOutData.stream().map(el -> new BigDecimal(el.get("totalMoney").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalReturn = iPage.getRecords().stream().map(FinancialCollectionStatistics::getTotalReceivedMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        totalAnalyse.put("sales", totalSales);
        totalAnalyse.put("debt", NumberUtil.add(paymentAgentStatisticsVO.getNoPayMoney(), paymentAgentStatisticsVO.getNoReconciledMoney(), paymentPurchaseStatisticsVO.getNoPayMoney(), paymentPurchaseStatisticsVO.getNoReconciledMoney()));
        totalAnalyse.put("noReturn", NumberUtil.sub(totalSales, totalReturn));
        totalAnalyse.put("totalBalance", fundAccountList.stream().map(FundAccount::getTotalBalance).reduce(BigDecimal.ZERO, BigDecimal::add));
        totalAnalyse.put("balanceUpdateTime", fundAccountList.stream().max(Comparator.comparing(FundAccount::getUpdateTime)).get().getUpdateTime());

        result.put("totalAnalyse", totalAnalyse);
        return R.data(result);
    }

    @Scheduled(cron = "0 59 23 * * ?")
    public void analyseFinance(){
        Date startD = new Date();
        log.info("开始处理{}的数据", DateUtil.formatDate(startD));
        QueryWrapper<SalesOut> sQuery = new QueryWrapper<>();
        sQuery.between("order_time", DateUtil.beginOfDay(startD), DateUtil.endOfDay(startD));
        List<SalesOut> salesOuts = salesOutMapper.selectList(sQuery);
        QueryWrapper<WXApproval> aQuery = new QueryWrapper<>();
        aQuery.between("apply_time", DateUtil.beginOfDay(startD), DateUtil.endOfDay(startD));
        List<WXApproval> approvals = wxApprovalDao.selectList(aQuery);
        FinanceAnalyse fa = new FinanceAnalyse();
        if(CollectionUtil.isNotEmpty(salesOuts)){
            fa.setSales(salesOuts.stream().map(SalesOut::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
        }
        if(CollectionUtil.isNotEmpty(approvals)){
            // 其他支出
            // 报销支出
            BigDecimal approvalOut = approvals.stream().map(WXApproval::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            fa.setExpenses(approvalOut);
        }
        fa.setYear(DateUtil.year(startD));
        fa.setMonth(DateUtil.month(startD) + 1);
        fa.setDay(DateUtil.dayOfMonth(startD));
        financeAnalyseMapper.insert(fa);
    }

    public List<String> generateMonthList(Date endTime,  Date startTime) {
        // 转换为LocalDate
        LocalDate startDate = startTime.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = endTime.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();

        // 获取年月对象
        YearMonth startYearMonth = YearMonth.from(startDate);
        YearMonth endYearMonth = YearMonth.from(endDate);

        // 创建月份列表
        List<String> monthList = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM");

        // 遍历所有月份
        for (YearMonth current = startYearMonth;
             !current.isAfter(endYearMonth);
             current = current.plusMonths(1)) {
            monthList.add(current.format(formatter));
        }

        return monthList;
    }
}
